
package com.eworking.eim.message;

import java.io.File;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.json.JSONObject;

import android.content.ContentValues;

import com.eworking.eim.EIMCallBack;
import com.eworking.eim.EIMChatManager;
import com.eworking.eim.EIMChatOptions;
import com.eworking.eim.EIMConfig;
import com.eworking.eim.EIMConstants;
import com.eworking.eim.cloud.CloudOperationCallback;
import com.eworking.eim.cloud.HttpFileManager;
import com.eworking.eim.encrypt.EIMEncryptUtils;
import com.eworking.eim.message.body.FileMessageBody;
import com.eworking.eim.message.body.ImageMessageBody;
import com.eworking.eim.message.body.VideoMessageBody;
import com.eworking.eim.packet.EIMEncryptPacketExtension;
import com.eworking.eim.util.EIMLog;
import com.eworking.eim.util.ImageUtil;

public class EIMSendMessageThread implements Runnable {
    
    /** 日志输出标记 */
    private static final String _TAG = EIMSendMessageThread.class.getSimpleName();
    
    /** 单聊 */
    private Chat chat = null;
    
    /** 群聊 */
    private MultiUserChat multiUserChat = null;
    
    /** 消息实体对象 */
    private EIMMessage message = null;
    
    private EIMCallBack callback = null;
    
    /** 线程等待时间 */
    private static final int _WAIT_TIME_OUT = 60;
    
    /** 等待回执的集合 */
    public static Map<String, Object> sendLocks = new Hashtable<String, Object>();
    
    private Object locked = new Object();
    
    public EIMSendMessageThread(Chat chat, EIMMessage message, EIMCallBack callback) {
        this.chat = chat;
        this.message = message;
        this.callback = callback;
    }
    
    public EIMSendMessageThread(MultiUserChat multiUserChat, EIMMessage message, EIMCallBack callback) {
        this.multiUserChat = multiUserChat;
        this.message = message;
        this.callback = callback;
    }
    
    @Override
    public void run() {
        this.message.status = EIMMessage.Status.INPROGRESS;
        switch (this.message.type.ordinal()) {
        
            case 1:
            case 4:
                // 文本消息、地理位置消息
                sendMessage();
                return;
                
            case 2:
                // 图片消息
                sendImageMessage();
                return;
            case 5:
                // 文件消息
                sendFileMessage();
                return;
            case 3:
                // 语音消息
                sendVideoMessage();
                return;
        }
    }
    
    private void sendMessage() {
        try {
            // 将消息实体转换为Json字符串[明文]
            String strMessage = EIMMessageEncoder.convertMsgToJSON(message, false);
            Message msgPacket = new Message();
            msgPacket.setPacketID(this.message.getMsgId());
            // IM参数信息
            EIMChatOptions chatOptions = EIMChatManager.getInstance().getChatOptions();
            // 启用加密 [密文]
            String strEncryptMessage = "";
            if (chatOptions.getUseEncryption()) {
                strEncryptMessage = EIMEncryptUtils.encryptMessage(strMessage, this.message.getTo());
                msgPacket.addExtension(new EIMEncryptPacketExtension());
            }
            msgPacket.setBody(strEncryptMessage);
            // 如果需要等待服务器回执，则添加到等待回执集合中
            if (chatOptions.getRequireServerAck()) {
                addSendLock(msgPacket.getPacketID(), this.locked);
            }
            // 发送群组消息
            if (this.message.chatType == EIMMessage.ChatType.GroupChat) {
                msgPacket.setType(Message.Type.groupchat);
                msgPacket.setTo(this.multiUserChat.getRoom());
                this.multiUserChat.sendMessage(msgPacket);
            } else {
                // 单聊
                this.chat.sendMessage(msgPacket);
            }
            // 如果需要等待服务器回执，则等待60S，如果60S没有收到回执则为发送失败
            if (chatOptions.getRequireServerAck()) {
                synchronized (this.locked) {
                    this.locked.wait(_WAIT_TIME_OUT * 1000);
                }
                if (sendLocks.remove(msgPacket.getPacketID()) != null) {
                    EIMLog.e(_TAG, "没有收到服务器的回执消息：" + msgPacket.getPacketID());
                    this.message.status = EIMMessage.Status.FAIL;
                    updateMsgState();
                    if (this.callback != null) {
                        this.callback.onError(EIMCallBack.ERROR_SEND, "没有收到服务器的回执");
                    }
                    return;
                }
            }
            this.message.msgId = msgPacket.getPacketID();
            this.message.status = EIMMessage.Status.SUCCESS;
            updateMsgState();
            if (this.callback != null) {
                this.callback.onSuccess();
            }
        } catch (Exception e) {
            this.message.status = EIMMessage.Status.FAIL;
            updateMsgState();
            if (this.callback != null) {
                this.callback.onError(EIMCallBack.ERROR_SEND, e.toString());
            }
        }
    }
    
    private void sendImageMessage() {
        try {
            final ImageMessageBody imageMessageBody = (ImageMessageBody) this.message.getMessageBody();
            // 图片本地地址
            String strLocalURL = imageMessageBody.localUrl;
            File imageFile = null;
            if (strLocalURL != null) {
                imageFile = new File(strLocalURL);
                if (!imageFile.exists()) {
                    // 缩略图地址
                    strLocalURL = this.getThumbnailImagePath(strLocalURL);
                    imageFile = new File(strLocalURL);
                }
            }
            if (imageFile == null || !imageFile.exists()) {
                if (this.callback != null) {
                    this.callback.onError(EIMCallBack.ERROR_SEND, "图片文件不存在：" + strLocalURL);
                }
            }
            // 用户删除缩略图
            boolean isNeedDelFile = false;
            if (!imageMessageBody.sendOriginalImage) {
                // 生成缩略图地址
                String scaledImage =
                    ImageUtil.getScaledImage(EIMConfig.getInstance().getApplicationContext(), strLocalURL);
                if (scaledImage.equals(strLocalURL)) {
                    EIMLog.d("sender", "send scaled image:" + scaledImage);
                    isNeedDelFile = true;
                    imageFile = new File(scaledImage);
                }
                strLocalURL = scaledImage;
            }
            
            final boolean isNeedDelFile_bak = isNeedDelFile;
            final File imageFile_bak = imageFile;
            
            // 远程文件服务器(文件云存储)
            HttpFileManager httpFileManager =
                new HttpFileManager(EIMConfig.getInstance().getApplicationContext(), EIMConfig.ARCHIVE_SERVER);
            final String strRemoteFilePath = this.getBaseUrlByAppKey();
            EIMLog.d(_TAG, "远程文件服务器路径:" + strRemoteFilePath);
            final EIMChatOptions chatOptions = EIMChatManager.getInstance().getChatOptions();
            // 需要加密
            if (chatOptions.getUseEncryption()) {
                strLocalURL = EIMEncryptUtils.encryptFile(strLocalURL, this.message.getTo());
            }
            Map<String, String> paramMap = new HashMap<String, String>();
            paramMap.put("restrict-access", "true");
            paramMap.put("Authorization", "Bearer " + EIMConfig.getInstance().getAccessToken());
            // 将文件上传至远程服务器上（云存储）
            httpFileManager.uploadFile(strLocalURL, strRemoteFilePath, EIMConfig.getInstance().getEntCode(), null,
                paramMap, new CloudOperationCallback() {
                    
                    @Override
                    public void onSuccess(String paramString) {
                        String strOriginalUUID = "";
                        String strOriginalSecret = "";
                        try {
                            JSONObject jsonObject = new JSONObject(paramString);
                            JSONObject entity = jsonObject.getJSONArray(EIMConstants._TOKEN_ENTITY).getJSONObject(0);
                            strOriginalUUID = entity.getString("uuid");
                            if (entity.has(EIMConstants._SHARE_SERCRET)) {
                                strOriginalSecret = entity.getString(EIMConstants._SHARE_SERCRET);
                            }
                        } catch (Exception localException1) {
                            EIMLog.e(_TAG, "远程文件解析错误：" + strRemoteFilePath);
                        }
                        try {
                            // 缩略图
                            String strThumbSecret = "";
                            String strThumbRemotePath = "";
                            if (chatOptions.getUseEncryption()) {
                                EIMLog.d("sender", "start to upload encrypted thumbnail");
                                Map<String, String> map = uploadEncryptedThumbnailImage(imageFile_bak, message);
                                String strUUID = map.get("uuid");
                                strThumbSecret = map.get("secret");
                                strThumbRemotePath = strRemoteFilePath + strUUID;
                                EIMLog.d("sender", "encryptd thumbnail uploaded to:" + strThumbRemotePath);
                            }
                            // 原图路径
                            String strOriginaRemoteURL = strRemoteFilePath + strOriginalUUID;
                            strOriginaRemoteURL = strOriginaRemoteURL.replaceAll("#", "%23");
                            // 缩略图
                            strThumbRemotePath = strThumbRemotePath.replaceAll("#", "%23");
                            imageMessageBody.remoteUrl = strOriginaRemoteURL;
                            imageMessageBody.thumbnailUrl =
                                ((android.text.TextUtils.isEmpty(strThumbRemotePath)) ? strOriginaRemoteURL
                                    : strThumbRemotePath);
                            imageMessageBody.secret = strOriginalSecret;
                            imageMessageBody.thumbnailSecret = strThumbSecret;
                            sendMessage();
                            EIMLog.d("sender", "sent msg successfully:" + message.toString());
                        } catch (Exception localException2) {
                            localException2.printStackTrace();
                            if (callback != null) {
                                callback.onProgress(100, null);
                                callback.onError(-2, localException2.toString());
                            }
                        }
                        if (isNeedDelFile_bak)
                            imageFile_bak.delete();
                    }
                    
                    @Override
                    public void onProgress(int flag) {
                        message.progress = flag;
                        if (callback != null)
                            callback.onProgress(flag, null);
                        
                    }
                    
                    @Override
                    public void onError(String paramString) {
                        EIMLog.d(_TAG, "上传文件失败:" + paramString);
                        if (isNeedDelFile_bak)
                            imageFile_bak.delete();
                        message.status = EIMMessage.Status.FAIL;
                        updateMsgState();
                        if (callback != null) {
                            callback.onProgress(100, null);
                            callback.onError(EIMCallBack.ERROR_SEND, paramString);
                        }
                    }
                });
        } catch (Exception e) {
            if (callback != null) {
                callback.onProgress(EIMCallBack.ERROR_SEND, null);
            }
        }
    }
    
    private void sendFileMessage() {
        File file = null;
        final FileMessageBody fileMessageBody = (FileMessageBody) this.message.getMessageBody();
        // 本地路径
        String strLocalURL = fileMessageBody.localUrl;
        if (strLocalURL != null)
            file = new File(strLocalURL);
        if ((file == null) || (!(file.exists()))) {
            if (this.callback != null)
                callback.onError(EIMCallBack.ERROR_FILE_NOT_FOUND, "文件不存在");
            return;
        }
        // 加密处理
        EIMChatOptions chatOptions = EIMChatManager.getInstance().getChatOptions();
        if (chatOptions.getUseEncryption()) {
            strLocalURL = EIMEncryptUtils.encryptFile(strLocalURL, message.getTo());
        }
        EIMLog.d(_TAG, "start to send file:" + strLocalURL + " size:" + file.length());
        // 文件云存储
        HttpFileManager httpFileManager =
            new HttpFileManager(EIMConfig.getInstance().getApplicationContext(), EIMConfig.ARCHIVE_SERVER);
        // 远程文件路径
        final String strRemoteFilePath = getBaseUrlByAppKey();
        HashMap<String, String> localHashMap = new HashMap<String, String>();
        localHashMap.put("restrict-access", "true");
        localHashMap.put("Authorization", "Bearer " + EIMConfig.getInstance().getAccessToken());
        httpFileManager.uploadFile(strLocalURL, strRemoteFilePath, EIMConfig.getInstance().getEntCode(), null,
            localHashMap, new CloudOperationCallback() {
                
                @Override
                public void onSuccess(String paramString) {
                    try {
                        String strUUID = "";
                        String strSecret = "";
                        try {
                            JSONObject jsonObject = new JSONObject(paramString);
                            JSONObject entityJSONObject = jsonObject.getJSONArray(EIMConstants._TOKEN_ENTITY).getJSONObject(0);
                            strUUID = entityJSONObject.getString("uuid");
                            if (entityJSONObject.has(EIMConstants._SHARE_SERCRET)) {
                                strSecret = entityJSONObject.getString(EIMConstants._SHARE_SERCRET);
                            }
                        } catch (Exception e) {
                            if ((e != null) && (e.getMessage() != null))
                                EIMLog.d("sendFileMessage", e.getMessage());
                        }
                        // 远程文件路径
                        String strRemoteURL = strRemoteFilePath + strUUID;
                        strRemoteURL = strRemoteURL.replaceAll("#", "%23").replaceAll(" ", "%20");
                        fileMessageBody.remoteUrl = strRemoteURL;
                        fileMessageBody.secret = strSecret;
                        // 发送消息
                        sendMessage();
                        EIMLog.d("sender", "sent msg successfully:" + message.toString());
                    } catch (Exception localException1) {
                        if (callback != null) {
                            callback.onProgress(100, null);
                            callback.onError(-2, localException1.toString());
                        }
                    }
                }
                
                @Override
                public void onProgress(int paramInt) {
                    message.progress = paramInt;
                    if (callback != null)
                        callback.onProgress(paramInt, null);
                }
                
                @Override
                public void onError(String paramString) {
                    EIMLog.d("sender", "upload error:" + paramString);
                    message.status = EIMMessage.Status.FAIL;
                    updateMsgState();
                    if (callback != null) {
                        callback.onProgress(100, null);
                        callback.onError(-2, paramString);
                    }
                }
            });
    }
    
    private void sendVideoMessage() {
        final VideoMessageBody videoMessageBody = (VideoMessageBody) message.getMessageBody();
        // 本地地址
        String strLocalURL = videoMessageBody.localUrl;
        final String strThumFilePath = videoMessageBody.localThumb;
        File localFile = new File(strLocalURL);
        if ((strLocalURL == null) || (!(localFile.exists()))) {
            if (callback != null)
                callback.onError(EIMCallBack.ERROR_FILE_NOT_FOUND, "video file doesn't exist");
            return;
        }
        if ((strThumFilePath == null) || (!(new File(strThumFilePath).exists()))) {
            if (callback != null)
                callback.onError(EIMCallBack.ERROR_FILE_NOT_FOUND, "video thumb file doesn't exist");
            return;
        }
        HttpFileManager localHttpFileManager =
            new HttpFileManager(EIMConfig.getInstance().getApplicationContext(), EIMConfig.ARCHIVE_SERVER);
        // 远程文件路径
        final String strRemoteFilePath = getBaseUrlByAppKey();
        EIMLog.d("sender", "remote file path:" + strRemoteFilePath);
        // 启用加密
        EIMChatOptions localEIMChatOptions = EIMChatManager.getInstance().getChatOptions();
        if (localEIMChatOptions.getUseEncryption()) {
            strLocalURL = EIMEncryptUtils.encryptFile(strLocalURL, message.getTo());
        }
        HashMap<String, String> localHashMap = new HashMap<String, String>();
        localHashMap.put("restrict-access", "true");
        localHashMap.put("Authorization", "Bearer " + EIMConfig.getInstance().getAccessToken());
        localHttpFileManager.uploadFile(strLocalURL, strRemoteFilePath, EIMConfig.getInstance().getEntCode(), null,
            localHashMap, new CloudOperationCallback() {
                
                public void onSuccess(String paramString) {
                    // 原图
                    String strOrginialUUID = "";
                    String strOrginialSecret = "";
                    try {
                        JSONObject jsonObject = new JSONObject(paramString);
                        JSONObject entityJSONObject = jsonObject.getJSONArray(EIMConstants._TOKEN_ENTITY).getJSONObject(0);
                        strOrginialUUID = entityJSONObject.getString("uuid");
                        if (entityJSONObject.has(EIMConstants._SHARE_SERCRET)) {
                            strOrginialSecret = ((JSONObject) entityJSONObject).getString(EIMConstants._SHARE_SERCRET);
                        }
                    } catch (Exception localException1) {
                        EIMLog.e("sender", "json parse exception remotefilePath:" + strRemoteFilePath);
                    }
                    try {
                        EIMLog.d("sender", "start to upload encrypted thumbnail");
                        Map<String, String> localMap =
                            uploadEncryptedThumbnailImage(new File(strThumFilePath), message);
                        // 缩略图
                        String strThumbUUID = localMap.get("uuid");
                        String strThumbSecret = localMap.get("secret");
                        String strThumbRemoteURL = strRemoteFilePath + strThumbUUID;
                        EIMLog.d("sender", "thumbail uploaded to:" + strThumbRemoteURL);
                        
                        // 原图路径
                        String strRemoteURL = strRemoteFilePath + strOrginialUUID;
                        strRemoteURL = strRemoteURL.replaceAll("#", "%23");
                        // 缩略图路径
                        strThumbRemoteURL = strThumbRemoteURL.replaceAll("#", "%23");
                        videoMessageBody.remoteUrl = strRemoteURL;
                        videoMessageBody.thumbnailUrl =
                            ((android.text.TextUtils.isEmpty(strThumbRemoteURL)) ? strRemoteURL : strThumbRemoteURL);
                        videoMessageBody.secret = strOrginialSecret;
                        videoMessageBody.thumbnailSecret = strThumbSecret;
                        // 发送消息
                        sendMessage();
                        EIMLog.d("sender", "sent msg sucessfully:" + message.toString());
                    } catch (Exception localException2) {
                        localException2.printStackTrace();
                        if (callback != null) {
                            callback.onProgress(100, null);
                            callback.onError(EIMCallBack.ERROR_SEND, localException2.getMessage());
                        }
                    }
                }
                
                public void onProgress(int paramInt) {
                    message.progress = paramInt;
                    if (callback != null)
                        callback.onProgress(paramInt, null);
                }
                
                public void onError(String paramString) {
                    EIMLog.d("sender", "upload error:" + paramString);
                    message.status = EIMMessage.Status.FAIL;
                    updateMsgState();
                    if (callback != null) {
                        callback.onProgress(100, null);
                        callback.onError(EIMCallBack.ERROR_SEND, paramString);
                    }
                }
            });
    }
    
    /**
     * 更新消息的状态
     * 
     * @param paramEIMMessage
     */
    private void updateMsgState() {
        ContentValues values = new ContentValues();
        values.put("status", this.message.status.ordinal());
        EIMMessageTable.getInstance().updateMessage(this.message.msgId, values);
    }
    
    public synchronized void addSendLock(String packetID, Object locked) {
        if (sendLocks == null) {
            sendLocks = new Hashtable<String, Object>();
        }
        sendLocks.put(packetID, locked);
    }
    
    public static synchronized void notifySendLock(String packetID) {
        if (sendLocks == null)
            return;
        Object object = sendLocks.remove(packetID);
        if (object != null)
            synchronized (object) {
                object.notify();
            }
    }
    
    /**
     * 获取缩略图的路径
     * 
     * @param strLocalURL 原图路径
     * @return
     */
    private String getThumbnailImagePath(String strLocalURL) {
        String strThumbURL = strLocalURL.substring(0, strLocalURL.lastIndexOf("/") + 1);
        strThumbURL =
            strThumbURL + "th" + strLocalURL.substring(strLocalURL.lastIndexOf("/") + 1, strLocalURL.length());
        EIMLog.d(_TAG, "original image path:" + strLocalURL);
        EIMLog.d(_TAG, "thum image path:" + strThumbURL);
        return strThumbURL;
    }
    
    /**
     * 获取远程文件服务器的地址
     * 
     * @return
     */
    private String getBaseUrlByAppKey() {
        String str = "";
        if (EIMConfig.ARCHIVE_SERVER.contains("http"))
            str =
                EIMConfig.ARCHIVE_SERVER + "/" + EIMConfig.getInstance().getEntCode().replaceFirst("#", "/")
                    + "/chatfiles/";
        else
            str =
                "https://" + EIMConfig.ARCHIVE_SERVER + "/"
                    + EIMConfig.getInstance().getEntCode().replaceFirst("#", "/") + "/chatfiles/";
        return str;
    }
    
    /**
     * 上传加密的缩略图文件
     * 
     * @param paramFile
     * @param paramEIMMessage
     * @return
     */
    private Map<String, String> uploadEncryptedThumbnailImage(File paramFile, EIMMessage paramEIMMessage) {
        final HashMap<String, String> localHashMap1 = new HashMap<String, String>();
        int size = 100;
        String strThumbURL = ImageUtil.getThumbnailImage(paramFile.getAbsolutePath(), size);
        EIMChatOptions localEIMChatOptions = EIMChatManager.getInstance().getChatOptions();
        if (localEIMChatOptions.getUseEncryption())
            strThumbURL = EIMEncryptUtils.encryptFile(strThumbURL, paramEIMMessage.getTo());
        HttpFileManager localHttpFileManager =
            new HttpFileManager(EIMConfig.getInstance().getApplicationContext(), EIMConfig.ARCHIVE_SERVER);
        String strRemoteURL = getBaseUrlByAppKey();
        HashMap<String, String> paramMap = new HashMap<String, String>();
        paramMap.put("restrict-access", "true");
        paramMap.put("Authorization", "Bearer " + EIMConfig.getInstance().getAccessToken());
        localHttpFileManager.uploadFile(strThumbURL, strRemoteURL, EIMConfig.getInstance().getEntCode(), null,
            paramMap, new CloudOperationCallback() {
                
                public void onSuccess(String paramString) {
                    EIMLog.d("sender", "encrypted thumbnail uploaded");
                    String uuid = "";
                    String secret = "";
                    try {
                        JSONObject localJSONObject1 = new JSONObject(paramString);
                        JSONObject localJSONObject2 =
                            localJSONObject1.getJSONArray(EIMConstants._TOKEN_ENTITY).getJSONObject(0);
                        uuid = localJSONObject2.getString("uuid");
                        if (localJSONObject2.has(EIMConstants._SHARE_SERCRET)) {
                            secret = localJSONObject2.getString(EIMConstants._SHARE_SERCRET);
                        }
                    } catch (Exception localException) {
                    }
                    localHashMap1.put("uuid", uuid);
                    localHashMap1.put("secret", secret);
                }
                
                public void onError(String paramString) {
                    EIMLog.e("sender", "encrypted thumbnail upload error:" + paramString);
                }
                
                public void onProgress(int pint) {
                }
            });
        return localHashMap1;
    }
}
